How to add Codepen in Markdown X ?
anyone know how to add markdown x editor codepen
i don't understand doc if there is video or any
https://devdojo.com/markdownx/docs/concepts/liquid-tags
PostsEditor.php
<?php
namespace App\Http\Livewire\Dashboard;
use App\Models\Post;
use Livewire\Component;
use Livewire\WithFileUploads;
use Illuminate\Support\Str;
use Validator;
class PostsEditor extends Component
{
use WithFileUploads;
public $post;
public $image;
protected $listeners = [
'markdown-x:update' => 'updateBody',
];
protected $rules = [
'post.title' => 'required|min:6',
'post.body' => 'required|min:6',
'post.image' => '',
'post.slug' => '',
'post.status' => '',
'post.excerpt' => '',
'post.type' => '',
'post.featured' => '',
'post.meta_title' => '',
'post.meta_description' => '',
'post.meta_schema' => '',
'post.meta_data' => '',
'image' => 'nullable|image|max:5120',
];
public function mount(Post $post)
{
if (isset($post)) {
$this->post = $post;
} else {
$this->post = new Post;
}
}
public function savePost()
{
$validator = Validator::make($this->getDataForValidation($this->rules), $this->rules);
if ($validator->fails()) {
$this->dispatchBrowserEvent('notification-show', [
'type' => 'error',
'message' => str_replace('post.', '', $validator->errors()->first())
]);
return;
}
$this->validate();
$this->post->user_id = auth()->user()->id;
if (!isset($this->post->id)) {
$this->post->slug = Str::slug($this->post->title);
}
if ($this->image) {
$this->post->image = $this->image->store('images');
$this->image = null;
}
foreach ($this->post->toArray() as $column => $value) {
if (is_null($value) && $column != 'image') {
unset($this->post->{$column});
}
}
$this->post->save();
$this->dispatchBrowserEvent('set-url', [
'url' => '/dashboard/posts/edit/' . $this->post->id,
]);
$this->dispatchBrowserEvent('notification-show', [
'type' => 'success',
'message' => 'Successfully saved post.'
]);
}
public function updateBody($value)
{
$this->post->body = $value;
}
public function delete(){
$this->post->delete();
session()->flash('notification',
[
'type' => 'success',
'message' => 'Successfully Deleted Post'
]);
return redirect('/dashboard');
}
public function removeTemporaryImage()
{
$this->image = null;
}
public function removeImage()
{
$this->post->image = null;
}
public function render()
{
return view('livewire.dashboard.posts-editor')->extends('dashboard.layout');
}
}
how to insert codepen code plz comment below
Hi there,
You can implement Liquid tags by following the steps here:
We recently had a similar discussion here where I've shared the steps on how to implement that:
Let me know how it goes.
Regards,
Bobby
now i got this 404
MarkdownX.php my code
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use GrahamCampbell\Markdown\Facades\Markdown as MarkdownConverter;
class MarkdownX extends Component
{
public $content;
public $contentPreview;
public $name;
public $key;
public $style;
public $section = 'write';
/**
* Laravel livewire listeners, learn more at https://laravel-livewire.com/docs/events#event-listeners
*
* 'markdown-x-image-upload' => uploads image files from the editor
*/
protected $listeners = [
'markdown-x-image-upload' => 'upload',
'markdown-x-giphy-load' => 'getGiphyTrendingImages',
'markdown-x-giphy-search' => 'getGiphySearchImages'
];
/**
* Mount the MarkdownX component, you can pass the current content, the name for the textarea field,
* and a generic Key. This key can be specified so that way you can include multiple MarkdownX
* editors in a single page.
*
* @param string $content
* @param string $name
* @param string $key
* @return void
*/
public function mount($content = '', $name = '', $key = '')
{
$this->content = $content;
$this->name = $name;
$this->key = $key;
$this->updateContentPreview();
}
/**
* Anytime the editor is blurred, this function will be triggered and it will updated the $content,
* this will also emit an event to the parent component with the updated content.
*
* @param array $data
*/
public function update($data)
{
$content = $data['content'];
$this->content = $content;
$this->emitUp('markdown-x:update', $this->content);
}
/**
* When the content changes this function will fire an event with the updatedPmark
* content is being emitted to the parent component.
*
*/
public function updatedContent()
{
$this->emitUp('markdown-x:update', $this->content);
}
/**
* This function will update the Content Preview when user clicks on the Preview tab in the
* Markdown editor toolbar.
*
* Note: This function can be overwritten with your customer Markdown parser. This is the
* only function that will/can be changed when you upgrade to the latest version of the
* MarkdownX editor.
*
*/
// public function updateContentPreview(){
// $this->contentPreview = Str::markdown($this->content);
// }
public function updateContentPreview()
{
$this->contentPreview = $this->parseLiquidTags(Str::markdown($this->content));
}
public static function parseLiquidTags($html)
{
$matches = "";
// If we find at least one liquid tag
if (preg_match_all('/{% .* %}/', $html, $matches) && isset($matches[0])) {
// loop through each of the liquid tags
foreach ($matches[0] as $index => $match) {
// replace multiple spaces with single space
$matchArray = explode(" ", preg_replace('!\s+!', ' ', $match));
// gaurantee we have the first value and run specific function for specific tag
if ($matchArray[1]) {
switch ($matchArray[1]) {
case 'youtube':
$html = self::replaceYouTubeTag($html, $matchArray, $match);
break;
case 'codepen':
$html = self::replaceCodePenTag($html, $matchArray, $match);
break;
case 'codesandbox':
$html = self::replaceCodeSandboxTag($html, $matchArray, $match);
break;
case 'buymeacoffee':
$html = self::replaceBuyMeACoffeeTag($html, $matchArray, $match);
break;
case 'giphy':
$html = self::replaceGiphyTag($html, $matchArray, $match);
break;
}
}
}
}
return $html;
}
public static function replaceCodePenTag($html, $tagArray, $original_string)
{
if (isset($tagArray[2])) {
$codepenEmbedURL = str_replace("/pen/", "/embed/", $tagArray[2]);
$defaultTag = 'default-tab=result';
if (isset($tagArray[3]) && $tagArray[3] != '%}') {
$defaultTag = $tagArray[3];
}
$codepenEmbed = '<div class="overflow-hidden border border-gray-100 rounded-lg"><iframe loading="lazy" height="600" style="width: 100%;" scrolling="no" src="' . $codepenEmbedURL . '?height=600&theme-id=24057&' . $defaultTag . '" frameborder="no" allowtransparency="true" allowfullscreen="true"></iframe></div>';
$html = str_replace($original_string, $codepenEmbed, $html);
}
return $html;
}
/**
* This function is called from the markdown-x view when the image file input has changed
* The following data is sent with the payload:
* {
* image: reader.result,
* name: file.name,
* key: key,
* text: ""
* }
*
* @param array $payload
* @return void
*/
public function upload($payload)
{
$payload = (object)$payload;
$path = 'images/' . strtolower(date('FY')) . '/';
$fullPath = '';
try {
$original_filename = pathinfo($payload->name, PATHINFO_FILENAME);
$filename = $original_filename;
$extension = explode('/', mime_content_type($payload->image))[1];
$filename_counter = 1;
// Make sure the filename does not exist, if it does make sure to add a number to the end 1, 2, 3, etc...
while (Storage::disk(config('markdownx.storage.disk'))->exists($path . $filename . '.' . $extension)) {
$filename = Str::slug($original_filename) . (string) ($filename_counter++);
}
$fullPath = $path . $filename . '.' . $extension;
// Get the Base64 string to store
@list($type, $file_data) = explode(';', $payload->image);
@list(, $file_data) = explode(',', $file_data);
$type = explode('/', $type)[1];
if (!in_array($type, config('markdownx.image.allowed_file_types'))) {
$this->dispatchBrowserEvent('markdown-x-image-uploaded', [
'status' => 400,
'message' => 'File type not supported. Must be of type ' . implode(', ', config('markdownx.image.allowed_file_types')),
'key' => $payload->key,
'text' => $payload->text
]);
return;
}
Storage::disk(config('markdownx.storage.disk'))->put($fullPath, base64_decode($file_data), 'public');
$this->dispatchBrowserEvent('markdown-x-image-uploaded', [
'status' => 200,
'message' => 'Successfully uploaded image.',
'path' => str_replace(' ', '%20', Storage::url($fullPath)),
'key' => $payload->key,
'text' => $payload->text,
'name' => $payload->name
]);
} catch (Exception $e) {
$this->dispatchBrowserEvent('markdown-x-image-uploaded', [
'status' => 400,
'message' => 'Error when trying to upload.',
'key' => $payload->key,
'text' => $payload->text
]);
}
}
public function getGiphyImages($payload)
{
$api_key = config('markdownx.integrations.giphy.api_key');
$response = Http::get('https://api.giphy.com/v1/gifs/trending', [
'api_key' => $api_key,
'limit' => 30,
'rating' => 'pg'
]);
if ($response->ok()) {
$this->sendResultsToView($response);
}
}
public function getGiphyTrendingImages($payload)
{
$api_key = config('markdownx.integrations.giphy.api_key');
$response = Http::get('https://api.giphy.com/v1/gifs/trending', [
'api_key' => $api_key,
'limit' => 30,
'rating' => 'pg'
]);
if ($response->ok()) {
$this->sendResultsToView($response, $payload['key']);
}
}
public function getGiphySearchImages($payload)
{
$api_key = config('markdownx.integrations.giphy.api_key');
$response = Http::get('api.giphy.com/v1/gifs/search', [
'api_key' => $api_key,
'q' => $payload['search'],
'limit' => 30,
'rating' => 'pg'
]);
if ($response->ok()) {
$this->sendResultsToView($response, $payload['key']);
}
}
public function sendResultsToView($response, $key)
{
$parse_giphy_results = [];
foreach ($response->json()['data'] as $result) {
array_push(
$parse_giphy_results,
[
'image' => $result['images']['fixed_height_small']['url'],
'embed' => $result['embed_url']
]
);
}
$this->dispatchBrowserEvent('markdown-x-giphy-results', [
'status' => 200,
'message' => 'Successfully returned results.',
'results' => $parse_giphy_results,
'key' => $key,
]);
}
/**
* Render the markdown-x view. Hazah!
*
*/
public function render()
{
return view('livewire.markdown-x');
}
}
Hi there,
I was able to replicate the problem. The bellow method should work as expected:
public static function replaceCodePenTag($html, $tagArray, $original_string){
if(isset($tagArray[2]) && isset($tagArray[3])){
$codepenEmbedLink = $tagArray[2] . ' ' .$tagArray[3];
preg_match_all('/<a[^>]+href=([\'"])(?<href>.+?)\1[^>]*>/i', $codepenEmbedLink, $result);
if (empty($result['href'])) {
return $html;
}
$codepenEmbed = $result['href'][0];
$codepenEmbedURL = str_replace("/pen/", "/embed/", $codepenEmbed);
$defaultTag = 'default-tab=result';
if(isset($tagArray[4]) && $tagArray[4] != '%}'){
$defaultTag = $tagArray[4];
}
$codepenEmbed = '<div class="overflow-hidden border border-gray-100 rounded-lg"><iframe loading="lazy" height="600" style="width: 100%;" scrolling="no" src="' . $codepenEmbedURL . '?height=600&theme-id=24057&' . $defaultTag . '" frameborder="no" allowtransparency="true" allowfullscreen="true"></iframe></div>';
$html = str_replace($original_string, $codepenEmbed, $html);
}
return $html;
}
Let me know how it goes.
Best,
Bobby
it working only backend
but not show in frontend
Blade file
@extends('layouts.app')
@section('content')
@if($post->type == App\Models\Post::TYPE_POST)
<div class="absolute top-0 left-0 hidden w-full h-auto mt-32 bg-center bg-cover lg:block lg:h-96"
style="background-image:url('{{ Storage::url($post->image) }}')">
<div class="absolute w-full h-full bg-gradient-to-b from-transparent to-white"></div>
<div class="absolute w-full h-full bg-white opacity-80"></div>
</div>
<div class="box-content relative max-w-6xl mx-auto overflow-hidden lg:pt-12 lg:px-10 lg:rounded-md h-96">
<img src="{{ Storage::url($post->image) }}" class="object-cover w-full h-96 lg:rounded-md" />
</div>
@endif
<article class="px-6 py-20 mx-auto prose xl:prose-xl 2xl:prose-2xl lg:px-0">
<h1>{{ $post->title }}</h1>
{!! Str::markdown($post->body) !!}
</article>
@endsection
Hello,
In order for this to work, you would need to include the liquid tags method in your frontend controller too.
Basically, when passing the post body to the front end, you need to run it through the liquid tags method.
Best,
Bobby
how to in controller add ?
BlogController.php
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class BlogController extends Controller
{
public function home()
{
$featured = Post::where('featured', 1)->where('type', 'post')->first();
return view('home', compact('featured'));
}
public function post(Post $post)
{
return view('post', compact('post'));
}
}
Hi there,
It will work the same way as with the MarkdownX method. Just add the liquid tags method to that controller and then before passing the post to the view do:
$featured = Post::where('featured', 1)->where('type', 'post')->first();
$featured->body = $this->parseLiquidTags(Str::markdown($featured->body));
return view('home', compact('featured'));
Then in your Blade view, you can remove the Str::markdown
method and just display the content.
Best,
Bobby
Done Thanks
one more question. is this impact my page performance ?
Hello,
There should not be any performance impact as this is just a pure PHP function so there are no fancy external calls and it is just a single call to the database.
Of course as you are including external resources like codepen, this will make it so that your website loads more resources, but it is not related with the simple liquid tag parsing.